﻿#include "Json.h"
#include "json/filestream.h"
#include "json/prettywriter.h"
#include "json/stringbuffer.h"
#include "cocos2d.h"
#include "utils.h"

//JsonObject
JsonObject::JsonObject()
{
    m_document.SetObject();
}

JsonObject::JsonObject(const string& data)
{
    parse(data);
}

JsonObject::JsonObject(const rapidjson::Value& value)
{
    parse(jtoString(value));
}

JsonObject::~JsonObject()
{
}

void JsonObject::copyFrome(JsonObject& src)
{
    m_document.SetObject();
    parse(jtoString(src.getRoot()));
}

bool JsonObject::parse(const string& str)
{
	if (str.empty())
	{
		return false;
	}
    m_document.Parse<0>(str.c_str());
    return !m_document.HasParseError();
}

bool JsonObject::has(const string& key)const
{
    return m_document.HasMember(key.c_str());
}
//
string JsonObject::getString(const string& key)const
{
    auto iter = m_document.FindMember(key.c_str());
    return iter->value.GetString();
}
int JsonObject::getInt(const string& key)const
{
    auto iter = m_document.FindMember(key.c_str());
	if (iter->value.IsString()){
		return atoi(iter->value.GetString());
	}
    return iter->value.GetInt();
}

const rapidjson::Value& JsonObject::getValue(const string& key)const
{
	auto iter = m_document.FindMember(key.c_str());
	return iter->value;
}

const rapidjson::Value& JsonObject::getObject(const string& key)const
{
    auto iter = m_document.FindMember(key.c_str());
    return iter->value;
}

const rapidjson::Value& JsonObject::getArray(const string& key)const
{
    auto iter = m_document.FindMember(key.c_str());
    return iter->value;
}
//
void JsonObject::add(const string& key,const string& value)
{
	if (has(key))
	{
		m_document.RemoveMember(key.c_str());
	}
    rapidjson::Value p_name(rapidjson::kStringType);
	p_name.SetString(key.c_str(), (int)key.size(), m_document.GetAllocator());
	rapidjson::Value p_value(rapidjson::kStringType);
	p_value.SetString(value.c_str(), (int)value.size(), m_document.GetAllocator());
    //
	m_document.AddMember(p_name, p_value, m_document.GetAllocator());
}

void JsonObject::add(const string& key,int value)
{
	if (has(key))
	{
		m_document.RemoveMember(key.c_str());
	}
    rapidjson::Value p_name(rapidjson::kStringType);
	p_name.SetString(key.c_str(), (int)key.size(), m_document.GetAllocator());
	m_document.AddMember<int>(p_name, value, m_document.GetAllocator());
}

void JsonObject::add(const string& key,JsonObject& value)
{
	if (has(key))
	{
		m_document.RemoveMember(key.c_str());
	}
    rapidjson::Value p_name(rapidjson::kStringType);
    p_name.SetString(key.c_str(), (int)key.size(), m_document.GetAllocator());
    //重新装填object
    rapidjson::Value p_value(rapidjson::kObjectType);
    auto &obj = value.getRoot();
    addObject(obj, p_value, m_document);
	m_document.AddMember(p_name, p_value, m_document.GetAllocator());
}

void JsonObject::add(const string& key,JsonArray& value)
{
	if (has(key))
	{
		m_document.RemoveMember(key.c_str());
	}
	rapidjson::Value p_name(rapidjson::kStringType);
	p_name.SetString(key.c_str(), (int)key.size(), m_document.GetAllocator());
    //重新装填sonArray
    rapidjson::Value p_value(rapidjson::kArrayType);
    auto &ary = value.getRoot();
    addArray(ary, p_value,m_document);
    m_document.AddMember(p_name, p_value, m_document.GetAllocator());
}

//static
void JsonObject::addArrayValue(rapidjson::Value &value,rapidjson::Value &root,rapidjson::Document &document)
{
    if(value.IsInt()){
        root.PushBack<int>(value.GetInt(), document.GetAllocator());
    }else if(value.IsString()){
        const string vstr = value.GetString();
        rapidjson::Value p_value(rapidjson::kStringType);
        p_value.SetString(vstr.c_str(), (int)vstr.size(), document.GetAllocator());
        root.PushBack(value, document.GetAllocator());
    }
	else if (value.IsBool()){
		root.PushBack<bool>(value.GetBool(), document.GetAllocator());
	}
	else if (value.IsDouble()){
		root.PushBack<double>(value.GetDouble(), document.GetAllocator());
	}
	else if (value.IsInt64()){
		root.PushBack<int64_t>(value.GetInt64(), document.GetAllocator());
	}
	else if (value.IsUint()){
		root.PushBack<unsigned>(value.GetUint(), document.GetAllocator());
	}
	else if (value.IsUint64()){
		root.PushBack<uint64_t>(value.GetUint64(), document.GetAllocator());
	}
	else{
		cocos2d::log("unknow value %s", "addArrayValue");
	}
}
void JsonObject::addObjectValue(const string &key,rapidjson::Value &value,rapidjson::Value &root,rapidjson::Document &document)
{
	rapidjson::Value p_name(rapidjson::kStringType);
	p_name.SetString(key.c_str(), (int)key.size(), document.GetAllocator());
    if(value.IsInt()){
        root.AddMember<int>(p_name, value.GetInt(), document.GetAllocator());
    }else if(value.IsString()){
        const string vstr = value.GetString();
        rapidjson::Value p_value(rapidjson::kStringType);
        p_value.SetString(vstr.c_str(), (int)vstr.size(), document.GetAllocator());
        root.AddMember(p_name, p_value, document.GetAllocator());
	}
	else if (value.IsBool()){
		root.AddMember<bool>(p_name, value.GetBool(), document.GetAllocator());
	}
	else if (value.IsDouble()){
		root.AddMember<double>(p_name, value.GetDouble(), document.GetAllocator());
	}
	else if (value.IsInt64()){
		root.AddMember<int64_t>(p_name, value.GetInt64(), document.GetAllocator());
	}
	else if (value.IsUint()){
		root.AddMember<unsigned>(p_name, value.GetUint(), document.GetAllocator());
	}
	else if (value.IsUint64()){
		root.AddMember<uint64_t>(p_name, value.GetUint64(), document.GetAllocator());
	}
	else{
		cocos2d::log("unknow value key = %s", key.c_str());
	}
}

void JsonObject::addArray(rapidjson::Value &value,rapidjson::Value &root,rapidjson::Document &document)
{
    for (auto iter = value.Begin();iter!=value.End();iter++) {
        auto& obj = iter->Move();
        if(obj.IsObject()){
            rapidjson::Value j_obj(rapidjson::kObjectType);
            addObject(obj, j_obj,document);
            root.PushBack(j_obj, document.GetAllocator());
        }else if(obj.IsArray()){
            rapidjson::Value j_ary(rapidjson::kArrayType);
            addArray(obj, j_ary,document);
            root.PushBack(j_ary, document.GetAllocator());
        }else{
            addArrayValue(obj, root, document);
        }
    }
}

void JsonObject::addObject(rapidjson::Value &value,rapidjson::Value &root,rapidjson::Document &document)
{
    for (auto iter = value.MemberBegin();iter!=value.MemberEnd();iter++) {
        if(iter->value.IsObject()){
            rapidjson::Value j_obj(rapidjson::kObjectType);
            addObject(iter->value, j_obj,document);
            root.AddMember(iter->name, j_obj, document.GetAllocator());
        }else if(iter->value.IsArray()){
            rapidjson::Value j_ary(rapidjson::kArrayType);
            addArray(iter->value, j_ary,document);
            root.AddMember(iter->name, j_ary, document.GetAllocator());
        }else{
            addObjectValue(iter->name.GetString(), iter->value, root, document);
        }
    }
}
string JsonObject::jtoString(const rapidjson::Value& value)
{
    rapidjson::StringBuffer buffer;
    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
    value.Accept(writer);
    return buffer.GetString();
}

string JsonObject::toString()const
{
    return jtoString(m_document);
}

//JsonObject end
//
//JsonArray
JsonArray::JsonArray()
{
    m_document.SetArray();
}

JsonArray::JsonArray(const string& data)
{
    parse(data);
}

JsonArray::JsonArray(const rapidjson::Value& value)
{
    parse(JsonObject::jtoString(value));
}

JsonArray::~JsonArray()
{
    
}

void JsonArray::copyFrome(JsonArray& src)
{
    m_document.SetArray();
    parse(JsonObject::jtoString(src.getRoot()));
}

bool JsonArray::parse(const string& str)
{
    m_document.Parse<0>(str.c_str());
    return m_document.HasParseError();
}

bool JsonArray::has(const string& key)
{
    return m_document.HasMember(key.c_str());
}
//
int JsonArray::count()
{
    return m_document.Size();
}

rapidjson::Value& JsonArray::getVaue(const int index)
{
   return m_document[index];
}
//
void JsonArray::add(const string& value)
{
	rapidjson::Value p_value(rapidjson::kStringType);
	p_value.SetString(value.c_str(), value.size(), m_document.GetAllocator());
	m_document.PushBack(p_value, m_document.GetAllocator());
}

void JsonArray::add(int value)
{
	m_document.PushBack<int>(value, m_document.GetAllocator());
}

void JsonArray::add(JsonObject& value)
{
    //重新装填JsonObject
    rapidjson::Value p_value(rapidjson::kObjectType);
    auto &obj = value.getRoot();
    JsonObject::addObject(obj, p_value, m_document);
    m_document.PushBack(p_value, m_document.GetAllocator());
}

void JsonArray::add(JsonArray& value)
{
    //重新装填JsonArray
    rapidjson::Value p_value(rapidjson::kArrayType);
    auto &ary = value.getRoot();
    JsonObject::addArray(ary, p_value, m_document);
    m_document.PushBack(p_value, m_document.GetAllocator());
}

string JsonArray::toString()
{
    rapidjson::StringBuffer buffer;
    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
    m_document.Accept(writer);
    return buffer.GetString();
}
//JsonArray end
